package com.hdphone.zljutils.impl;

import android.content.Context;
import android.content.ContextWrapper;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.hdphone.zljutils.R;
import com.hdphone.zljutils.ZljUtils;
import com.hdphone.zljutils.inter.IToastUtil;

import java.lang.reflect.Field;

public class ToastUtilImpl implements IToastUtil {

    private TextView mTvContent;
    private Toast mToast;

    private void lazyInitToast() {
        if (mToast == null) {
            LayoutInflater inflater = LayoutInflater.from(ZljUtils.getApp());
            View view = inflater.inflate(R.layout.util_layout_toast, null);
            mTvContent = view.findViewById(R.id.toast2_msg);
            mToast = new Toast(ZljUtils.getApp());
            mToast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, ZljUtils.DIMEN().dip2px(160));
            if (mToast.getView() == null) {
                mToast.setView(view);
            }

            setContextCompat(mToast.getView(), new SafeToastContext(ZljUtils.getApp()));
        }
    }


    @Override
    public void showShortToast(@NonNull String s) {
        lazyInitToast();

        try {
            mToast.setDuration(Toast.LENGTH_SHORT);
            mTvContent.setText(s);
            mToast.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void showShortToast(int resId) {
        lazyInitToast();

        try {
            mToast.setDuration(Toast.LENGTH_SHORT);
            mTvContent.setText(resId);
            mToast.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void showLongToast(@NonNull String s) {
        lazyInitToast();

        try {
            mToast.setDuration(Toast.LENGTH_LONG);
            mTvContent.setText(s);
            mToast.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void showLongToast(int resId) {
        lazyInitToast();

        try {
            mToast.setDuration(Toast.LENGTH_LONG);
            mTvContent.setText(resId);
            mToast.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void setContextCompat(@NonNull View view, @NonNull Context context) {
        if (Build.VERSION.SDK_INT == 25) {
            try {
                Field field = View.class.getDeclaredField("mContext");
                field.setAccessible(true);
                field.set(view, context);
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }


    private final class SafeToastContext extends ContextWrapper {

        SafeToastContext(@NonNull Context base) {
            super(base);
        }


        @Override
        public Context getApplicationContext() {
            return new ApplicationContextWrapper(getBaseContext().getApplicationContext());
        }

        private final class ApplicationContextWrapper extends ContextWrapper {

            private ApplicationContextWrapper(@NonNull Context base) {
                super(base);
            }


            @Override
            public Object getSystemService(@NonNull String name) {
                if (Context.WINDOW_SERVICE.equals(name)) {
                    // noinspection ConstantConditions
                    return new WindowManagerWrapper((WindowManager) getBaseContext().getSystemService(name));
                }
                return super.getSystemService(name);
            }
        }


        private final class WindowManagerWrapper implements WindowManager {

            private static final String TAG = "WindowManagerWrapper";
            private final @NonNull
            WindowManager base;


            private WindowManagerWrapper(@NonNull WindowManager base) {
                this.base = base;
            }


            @Override
            public Display getDefaultDisplay() {
                return base.getDefaultDisplay();
            }


            @Override
            public void removeViewImmediate(View view) {
                base.removeViewImmediate(view);
            }


            @Override
            public void addView(View view, ViewGroup.LayoutParams params) {
                try {
                    Log.d(TAG, "WindowManager's addView(view, params) has been hooked.");
                    base.addView(view, params);
                } catch (BadTokenException e) {
                    Log.e(TAG, e.getMessage());
                } catch (Throwable throwable) {
                    Log.e(TAG, "[addView]", throwable);
                }
            }


            @Override
            public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
                base.updateViewLayout(view, params);
            }


            @Override
            public void removeView(View view) {
                base.removeView(view);
            }
        }
    }

}
